home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / ipServer / tcpSock.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-13  |  37.4 KB  |  1,468 lines

  1. /* 
  2.  * tcpSock.c --
  3.  *
  4.  *    Protocol-dependent routines to implement the semantics of
  5.  *    the socket operations defined in sockOps.c. The routines in
  6.  *    this file handle TCP stream sockets.
  7.  *
  8.  *    Based on the following 4.3BSD files:
  9.  *    "@(#)tcp_subr.c      7.13 (Berkeley) 12/7/87"
  10.  *    "@(#)tcp_usrreq.c 7.8 (Berkeley) 3/16/88"
  11.  *
  12.  *     To do:
  13.  *    1) fix bug in socket closing: sockPtr is not deallocated.
  14.  *
  15.  *
  16.  * Copyright 1987 Regents of the University of California
  17.  * All rights reserved.
  18.  * Permission to use, copy, modify, and distribute this
  19.  * software and its documentation for any purpose and without
  20.  * fee is hereby granted, provided that the above copyright
  21.  * notice appear in all copies.  The University of California
  22.  * makes no representations about the suitability of this
  23.  * software for any purpose.  It is provided "as is" without
  24.  * express or implied warranty.
  25.  */
  26.  
  27. #ifndef lint
  28. static char rcsid[] = "$Header: /sprite/src/daemons/ipServer/RCS/tcpSock.c,v 1.12 91/11/12 20:56:31 mottsmth Exp $ SPRITE (Berkeley)";
  29. #endif not lint
  30.  
  31.  
  32. #include "sprite.h"
  33. #include "inet.h"
  34. #include "netInet.h"
  35. #include "ipServer.h"
  36. #include "stat.h"
  37. #include "socket.h"
  38. #include "sockInt.h"
  39. #include "tcp.h"
  40. #include "tcpInt.h"
  41. #include "route.h"
  42.  
  43. /*
  44.  * Default size (in bytes) of a socket's send and receive buffers.
  45.  */
  46. #define SEND_SPACE    TCP_BUF_SIZE
  47. #define RECV_SPACE    TCP_BUF_SIZE
  48.  
  49.  
  50. static unsigned int    GetPort();
  51. static Boolean        ConnQueueFull();
  52. static Boolean        ConnQueueNotEmpty();
  53. static void        ConnQueueAppend();
  54. static Sock_SharedInfo    *ConnQueueNext();
  55. TCPControlBlock *curTCB;
  56.  
  57.  
  58.  
  59. /*
  60.  *----------------------------------------------------------------------
  61.  *
  62.  * TCP_SocketOpen --
  63.  *
  64.  *    This routine completes the TCP-dependent initialization of the
  65.  *    socket. A TCP control block is allocated and initialized. 
  66.  *    The send and receive buffers are also initialized.
  67.  *
  68.  * Results:
  69.  *    SUCCESS        - always returned.
  70.  *
  71.  * Side effects:
  72.  *    Memory for the TCP control block is allocated.
  73.  *
  74.  *----------------------------------------------------------------------
  75.  */
  76.  
  77. /*ARGSUSED*/
  78. ReturnStatus
  79. TCP_SocketOpen(sockPtr, userID)
  80.     Sock_SharedInfo    *sockPtr;    /* Socket to be initialized. */
  81.     int            userID;        /* Client's user ID. Ignored. */
  82. {
  83.     register TCPControlBlock *tcbPtr;
  84.  
  85.     tcbPtr = (TCPControlBlock *) malloc(sizeof(TCPControlBlock));
  86.     sockPtr->protoData = (ClientData) tcbPtr;
  87.  
  88.     bzero( (Address) tcbPtr, sizeof(*tcbPtr));
  89.     tcbPtr->state        = CLOSED;
  90.     tcbPtr->maxSegSize        = TCP_MAX_SEG_SIZE;
  91.     tcbPtr->flags        = 0;
  92.     /*
  93.      * Initialize the smoothed RTT to 0 so we can tell that we have no
  94.      * RTT estimate.  Set rttvar so that smooth RTT + 2 * rttVar gives
  95.      * reasonable initial retransmit time.
  96.      */
  97.     tcbPtr->srtt        = TCP_SRTT_BASE_TIME;
  98.     tcbPtr->rttvar        = TCP_SRTT_DEFLT_TIME << 2;
  99.     TCP_TIMER_RANGESET(tcbPtr->rxtcur, 
  100.     ((TCP_SRTT_BASE_TIME >> 2) + (TCP_SRTT_DEFLT_TIME << 2)) >> 1,
  101.     TCP_MIN_REXMT_TIME, TCP_MAX_REXMT_TIME);
  102.     tcbPtr->send.congWindow    = SEND_SPACE;
  103.     tcbPtr->send.cwSizeThresh    = 65535    /* XXX */;
  104.     List_Init(&tcbPtr->reassList);
  105.  
  106.     Sock_BufAlloc(sockPtr, SOCK_RECV_BUF, RECV_SPACE);
  107.     Sock_BufAlloc(sockPtr, SOCK_SEND_BUF, SEND_SPACE);
  108.     return(SUCCESS);
  109. }
  110.  
  111.  
  112. /*
  113.  *----------------------------------------------------------------------
  114.  *
  115.  * TCP_SocketClose --
  116.  *
  117.  *    Remove data from the socket's read and write queues and
  118.  *    deallocate the TCP control block.
  119.  *
  120.  *  To do:
  121.  *      1) make sure can free read/write queues (tcp may need to wait
  122.  *         for acks before the data can be freed).
  123.  *      2) reject waiting connection attempts
  124.  *
  125.  * Results:
  126.  *    SUCCESS        - the operation was successful.
  127.  *    FS_WOULD_BLOCK    - the socket can't be closed yet because some data
  128.  *              in the send buffer has not been ACKed.
  129.  *
  130.  * Side effects:
  131.  *    The TCB may be destroyed. A packet may be sent to the remote host.
  132.  *
  133.  *----------------------------------------------------------------------
  134.  */
  135.  
  136. ReturnStatus
  137. TCP_SocketClose(sockPtr)
  138.     Sock_SharedInfo    *sockPtr;    /* Socket to be closed. */
  139. {
  140.     register TCPControlBlock *tcbPtr;
  141.     tcbPtr = (TCPControlBlock *) sockPtr->protoData;
  142.  
  143.     /*
  144.      * The TCB will be NULL if the connection gets reset before
  145.      * being fully established.
  146.      */
  147.     if (tcbPtr == (TCPControlBlock *) NULL) {
  148.     return(SUCCESS);
  149.     }
  150.  
  151.  
  152.     switch (tcbPtr->state) {
  153.     /*
  154.      * If accepting connections, go through the queue of waiting 
  155.      * connections and drop them.
  156.      */
  157.     case LISTEN:
  158.         while (ConnQueueNotEmpty(sockPtr, FALSE)) {
  159.         Sock_InfoPtr    connPtr = ConnQueueNext(sockPtr);
  160.  
  161.         TCPDropConnection(connPtr, 
  162.                 (TCPControlBlock *) connPtr->protoData, 
  163.                 (ReturnStatus)NET_CONNECTION_RESET);
  164.         }
  165.  
  166.         /* Fall into ... */
  167.  
  168.     case CLOSED:
  169.     case SYN_SENT:
  170.     case SYN_RECEIVED:
  171.         TCPCloseConnection(sockPtr, tcbPtr);
  172.         return(SUCCESS);
  173.         break;
  174.  
  175.  
  176.     default:
  177.         if ((sockPtr->options & NET_OPT_LINGER) && (sockPtr->linger == 0)) {
  178.         /*
  179.          * If linger wanted and not lingering then drop the connection.
  180.          */
  181.         TCPDropConnection(sockPtr, tcbPtr, 
  182.                     (ReturnStatus)NET_CONNECTION_RESET);
  183.         } else {
  184.         Sock_Disconnecting(sockPtr);
  185.         Sock_BufRemove(sockPtr, SOCK_RECV_BUF, -1);
  186.  
  187.         switch (tcbPtr->state) {
  188.             case ESTABLISHED:
  189.             tcbPtr->state = FIN_WAIT_1;
  190.             break;
  191.  
  192.             case CLOSE_WAIT:
  193.             tcbPtr->state = LAST_ACK;
  194.             break;
  195.  
  196.             case FIN_WAIT_2:
  197.             case TIME_WAIT:
  198.             Sock_Disconnected(sockPtr);
  199.             break;
  200.  
  201.             case FIN_WAIT_1:
  202.             case LAST_ACK:
  203.             break;
  204.         }
  205.         (void) TCPOutput(sockPtr, tcbPtr);
  206.         }
  207.         break;
  208.     }
  209.     /*
  210.      * Tell the client that it has to wait for the remote host to 
  211.      * acknowledge our close.
  212.      */
  213.     return(FS_WOULD_BLOCK);
  214. }
  215.  
  216.  
  217. /*
  218.  *----------------------------------------------------------------------
  219.  *
  220.  * TCP_SocketRead --
  221.  *
  222.  *    Return data to a client doing a read on a TCP socket.
  223.  *    Normal or urgent ("out-of-band") data can be retreived.
  224.  *
  225.  * Results:
  226.  *    SUCCESS        - the operation was successful.
  227.  *    FS_WOULD_BLOCK    - the read queue was empty or didn't have
  228.  *              enough data to fill the buffer.
  229.  *
  230.  * Side effects:
  231.  *    Data can be removed from the receive buffer.
  232.  *
  233.  *----------------------------------------------------------------------
  234.  */
  235.  
  236. ReturnStatus
  237. TCP_SocketRead(privPtr, bufSize, buffer, amountReadPtr)
  238.     register Sock_PrivInfo *privPtr;    /* Socket with data. */
  239.     int        bufSize;        /* Amount of data to read. */
  240.     Address    buffer;            /* Place to store the data. */
  241.     int        *amountReadPtr;        /* Actual amount placed in buffer. */
  242. {
  243.     ReturnStatus status;
  244.     Sock_SharedInfo    *sharePtr = privPtr->sharePtr;
  245.     TCPControlBlock    *tcbPtr   = (TCPControlBlock *)sharePtr->protoData;
  246.     int recvFlags = privPtr->recvFlags | SOCK_BUF_STREAM;
  247.     int amtRead = 0;
  248.  
  249.     if (sharePtr->state != CONNECTED) {
  250.     return(NET_NOT_CONNECTED);
  251.     }
  252.  
  253.     /*
  254.      * The user wants urgent ("out-of-band") data.
  255.      */
  256.     if (recvFlags & NET_OUT_OF_BAND) {
  257.     /*
  258.      * If there's no urgent data or urgent data is supposed to remain
  259.      * in-line with other data or the urgent data is not available
  260.      * any more, then return an error.
  261.      */
  262.     if (((tcbPtr->urgentBufPos == 0) &&
  263.           !(sharePtr->flags & SOCK_URGENT_DATA_NEXT)) ||
  264.         Sock_IsOptionSet(sharePtr, NET_OPT_OOB_INLINE) ||
  265.         tcbPtr->flags & TCP_HAD_URGENT_DATA) {
  266.  
  267.         status = GEN_INVALID_ARG;
  268.     } else if (!(tcbPtr->flags & TCP_HAVE_URGENT_DATA)) {
  269.         /*
  270.          * There's urgent data but it's not yet 
  271.          */
  272.         status = FS_WOULD_BLOCK;
  273.     } else {
  274.  
  275.         amtRead = 1;
  276.         *buffer = tcbPtr->urgentData;
  277.         if (!(recvFlags & NET_PEEK)) {
  278.         /*
  279.          * If this is a destructive read, then turn off the HAVE bit
  280.          * and turn on the HAD bit to indicate the urgent data's 
  281.          * been read.
  282.          */
  283.         tcbPtr->flags ^= (TCP_HAVE_URGENT_DATA | TCP_HAD_URGENT_DATA);
  284.         }
  285.         status = SUCCESS;
  286.     }
  287.     } else {
  288.  
  289.     /*
  290.      * Return "normal" data to the user. 
  291.      */
  292.  
  293.     sharePtr->flags &= ~SOCK_URGENT_DATA_NEXT;
  294.     if ((tcbPtr->urgentBufPos > 0) && (bufSize > tcbPtr->urgentBufPos)) {
  295.         /*
  296.          * There's urgent data in the buffer -- just read enough normal 
  297.          * data until the position of the urgent data is reached.
  298.          */
  299.         bufSize = tcbPtr->urgentBufPos;
  300.     }
  301.  
  302.     status = Sock_BufFetch(sharePtr, recvFlags, bufSize, buffer, &amtRead, 
  303.             (Net_InetSocketAddr *) NULL);
  304.  
  305.     if (!(recvFlags & NET_PEEK)) {
  306.         tcbPtr->urgentBufPos -= amtRead;
  307.         if (tcbPtr->urgentBufPos == 0) {
  308.         sharePtr->flags |= SOCK_URGENT_DATA_NEXT;
  309.         }
  310.  
  311.         if (status == SUCCESS) {
  312.         /*
  313.          * See if we need to send a window update to the peer.
  314.          */
  315.         (void) TCPOutput(sharePtr, tcbPtr);
  316.         }
  317.     }
  318.     }
  319.  
  320.     if (amountReadPtr != (int *) NULL) {
  321.     *amountReadPtr = amtRead;
  322.     }
  323.  
  324.     if (status != FS_WOULD_BLOCK) {
  325.     privPtr->recvFlags = 0;
  326.     }
  327.     return(status);
  328. }
  329.  
  330. /*
  331.  *----------------------------------------------------------------------
  332.  *
  333.  * TCP_SocketWrite --
  334.  *
  335.  *    This routine appends the data to be written to the socket's
  336.  *    send buffer and calls the output routine to send the data to
  337.  *    the remote host.
  338.  *
  339.  * Results:
  340.  *    SUCCESS        - the operation was successful.
  341.  *    FS_WOULD_BLOCK    - no room in the buffer to hold the data.
  342.  *
  343.  * Side effects:
  344.  *    Packets containing the data may be sent.
  345.  *
  346.  *----------------------------------------------------------------------
  347.  */
  348.  
  349. ReturnStatus
  350. TCP_SocketWrite(privPtr, packetPtr, amtWrittenPtr)
  351.     Sock_PrivInfo    *privPtr;    /* Socket to write to. */ 
  352.     IPS_Packet        *packetPtr;    /* Packet descriptor containing 
  353.                      * data to be written. */
  354.     int            *amtWrittenPtr;    /* Actual amount of data written. */
  355. {
  356.     ReturnStatus status;
  357.     Sock_SharedInfo    *sharePtr = privPtr->sharePtr;
  358.  
  359.     if (sharePtr->state != CONNECTED) {
  360.     return(NET_NOT_CONNECTED);
  361.     }
  362.  
  363.     if ((privPtr->sendInfoValid) && 
  364.     (privPtr->sendInfo.flags & NET_OUT_OF_BAND)) {
  365.  
  366.     TCPControlBlock    *tcbPtr   = (TCPControlBlock *)sharePtr->protoData;
  367.  
  368.     status = Sock_BufAppend(sharePtr, SOCK_SEND_BUF, FALSE,
  369.         packetPtr->dataLen, packetPtr->data, packetPtr->base, 
  370.         (Net_InetSocketAddr *) NULL, amtWrittenPtr);
  371.  
  372.     /*
  373.      * According to RFC1011 "Assigned Internet Protocols" (May 1987), 
  374.      * the urgent pointer points to the last octet of urgent data.  
  375.      * We continue, however, to consider it to indicate the first octet 
  376.      * of data past the urgent section.  Otherwise, send.urgentPtr 
  377.      * should be one lower. (This is the same behavior as 4.3BSD).
  378.      */
  379.     if (status == SUCCESS) {
  380.         tcbPtr->send.urgentPtr = tcbPtr->send.unAck + 
  381.             Sock_BufSize(sharePtr, SOCK_SEND_BUF, SOCK_BUF_USED);
  382.         tcbPtr->force = TRUE;
  383.         (void) TCPOutput(sharePtr, tcbPtr);
  384.         tcbPtr->force = FALSE;
  385.     } else if (*amtWrittenPtr != 0) {
  386.         TCPOutput(sharePtr, tcbPtr);
  387.     }
  388.     } else {
  389.     status = Sock_BufAppend(sharePtr, SOCK_SEND_BUF, FALSE,
  390.         packetPtr->dataLen, packetPtr->data, packetPtr->base, 
  391.         (Net_InetSocketAddr *) NULL, amtWrittenPtr);
  392.     if (*amtWrittenPtr != 0) {
  393.         (void) TCPOutput(sharePtr, (TCPControlBlock *)sharePtr->protoData);
  394.     }
  395.     }
  396.  
  397.     if (status == SUCCESS) {
  398.     privPtr->sendInfoValid = FALSE;
  399.     }
  400.     return(status);
  401. }
  402.  
  403.  
  404. /*
  405.  *----------------------------------------------------------------------
  406.  *
  407.  * TCP_SocketSelect --
  408.  *
  409.  *    This routine checks the socket to see if there is
  410.  *    1) data in the receive buffer to be read (active sockets),
  411.  *    2) a new connection waiting (passive sockets),
  412.  *    3) space in the send buffer for new data.
  413.  *    4) urgent data to be read.
  414.  *
  415.  * Results:
  416.  *    An or'd combination of FS_READBLE, FS_WRITABLE, FS_EXCEPTION.
  417.  *
  418.  * Side effects:
  419.  *    None.
  420.  *
  421.  *----------------------------------------------------------------------
  422.  */
  423.  
  424. int
  425. TCP_SocketSelect(sockPtr)
  426.     register Sock_SharedInfo    *sockPtr;    /* Socket to be selected. */
  427. {
  428.     int flags = 0;
  429.     TCPControlBlock    *tcbPtr = (TCPControlBlock *)sockPtr->protoData;
  430.  
  431.     if (sockPtr->state == LISTENING) {
  432.     if (ConnQueueNotEmpty(sockPtr, TRUE)) {
  433.         flags |= FS_READABLE;
  434.     }
  435.     } else if (Sock_IsRecvStopped(sockPtr) || 
  436.           ((sockPtr->state == CONNECTED) &&
  437.           (Sock_BufSize(sockPtr, SOCK_RECV_BUF, SOCK_BUF_USED) > 0))) {
  438.     flags |= FS_READABLE;
  439.     }
  440.  
  441.     if (Sock_IsSendStopped(sockPtr) || 
  442.        ((sockPtr->state == CONNECTED) &&
  443.        (Sock_BufSize(sockPtr, SOCK_SEND_BUF, SOCK_BUF_FREE) > 0))) {
  444.     flags |= FS_WRITABLE;
  445.     }
  446.  
  447.     /*
  448.      * If the socket has been connecting to a remote peer and the
  449.      * connection has just become established, then say the socket is
  450.      * writable (the client waits for establishment by selecting for the 
  451.      * for writing). 
  452.      *
  453.      * This flag is good for 1 select call: it has to be reset so the socket
  454.      * won't be writable forerver.
  455.      */
  456.     if (sockPtr->justEstablished) {
  457.     flags |= FS_WRITABLE;
  458.     sockPtr->justEstablished = FALSE;
  459.     }
  460.  
  461.     if ((sockPtr->state == CONNECTED) &&
  462.     ((sockPtr->flags & SOCK_URGENT_DATA_NEXT) ||
  463.     (tcbPtr->urgentBufPos > 0))) {
  464.     flags |= FS_EXCEPTION;
  465.     }
  466.     return(flags);
  467. }
  468.  
  469.  
  470. /*
  471.  *----------------------------------------------------------------------
  472.  *
  473.  * TCP_SocketBind --
  474.  *
  475.  *    Does TCP-specific stuff for assigning the local address of a socket.
  476.  *
  477.  * Results:
  478.  *    SUCCESS            - the operation was successful.
  479.  *    NET_ADDRESS_NOT_AVAIL    - an invalid address was given.
  480.  *    GEN_NO_PERMISSION    - the user tried to use a privileged port
  481.  *                  and did not have super-user privilege.
  482.  *    NET_ADDRESS_IN_USE    - the local <address,port> is already in use.
  483.  *
  484.  * Side effects:
  485.  *    The socket's state changes and the local address is changed.
  486.  *
  487.  *----------------------------------------------------------------------
  488.  */
  489.  
  490. ReturnStatus
  491. TCP_SocketBind(sockPtr, addrPtr, userID)
  492.     register Sock_SharedInfo    *sockPtr;/* Socket to be bound. */
  493.     Net_InetSocketAddr        *addrPtr;/* The local address for the socket. */
  494.     int                userID;    /* User ID of the process. */
  495. {
  496.     Net_InetSocketAddr    temp;
  497.     temp = *addrPtr;
  498.  
  499.     /*
  500.      * If a specific Inetnet address is given, make sure it is valid for
  501.      * this host (i.e. it is one of the addresses assigned to the host).
  502.      */
  503.  
  504.     if (temp.address != Net_HostToNetInt(NET_INET_ANY_ADDR)) {
  505.     if (!Rte_ValidateAddress(temp.address)) {
  506.         if (ips_Debug) {
  507.         (void) fprintf(stderr, "TCP_SocketBind: address not valid\n");
  508.         }
  509.         return(NET_ADDRESS_NOT_AVAIL);
  510.     }
  511.     }
  512.  
  513.     if (temp.port == 0) {
  514.     temp.port = GetPort(temp.address);
  515.     } else {
  516.     Boolean wildcard;
  517.  
  518.     /*
  519.      * Make sure the given port is OK to use. If the port # is in
  520.      * the reserved range then make sure the user has super-user
  521.      * privileges. 
  522.      */
  523.  
  524.     if ((Net_NetToHostShort(temp.port) < INET_PRIV_PORTS) && 
  525.         (userID != PROC_SUPER_USER_ID)) {
  526.         if (ips_Debug) {
  527.         (void) fprintf(stderr,
  528.                    "TCP_SocketBind: no permission for port %d, user %d\n",
  529.                    temp.port, userID);
  530.         }
  531.         return(GEN_NO_PERMISSION);
  532.     }
  533.  
  534.     /*
  535.      * Check for the uniqueness of the new local <address,port> tuple
  536.      * among all TCP sockets.  The REUSE_ADDR option specifies the
  537.      * strictness of the check.  If the option is not set, then the
  538.      * local tuple can't be used by us if any other TCP socket is
  539.      * using it.  A looser check is made if the option is set:  we can
  540.      * use the local tuple even if it is used by other sockets but
  541.      * only if their remote tuple is not the <NET_INET_ANY_ADDR,0>
  542.      * wildcard.
  543.      */
  544.  
  545.     if (Sock_IsOptionSet(sockPtr, NET_OPT_REUSE_ADDR)) {
  546.         wildcard = FALSE;
  547.     } else {
  548.         wildcard = TRUE;
  549.     }
  550.  
  551.     if (Sock_Match(TCP_PROTO_INDEX, temp.address, temp.port,
  552.             Net_HostToNetInt(NET_INET_ANY_ADDR), 0, wildcard) != 
  553.                     (Sock_InfoPtr    ) NULL) {
  554.         if (ips_Debug) {
  555.         (void) fprintf(stderr, "TCP_SocketBind: address in use\n");
  556.         }
  557.         return(NET_ADDRESS_IN_USE);
  558.     }
  559.     }
  560.  
  561.     sockPtr->local = temp;
  562.     sockPtr->state = HAVE_LOCAL_ADDR;
  563.     return(SUCCESS);
  564. }
  565.  
  566.  
  567. /*
  568.  *----------------------------------------------------------------------
  569.  *
  570.  * TCP_SocketConnect --
  571.  *
  572.  *    Establishes a connection with a remote host.
  573.  *
  574.  * Results:
  575.  *    SUCCESS            - the operation was successful.
  576.  *    NET_ALREADY_CONNECTED    - the socket is already connected to a remote
  577.  *                  host.
  578.  *    NET_ADDRESS_NOT_AVAIL    - an invalid remote port was used.
  579.  *    NET_ADDRESS_IN_USE    - the remote <address, port> is already used
  580.  *                  by another socket.
  581.  *    FS_WOULD_BLOCK        - a packet has been sent to the remote
  582.  *                  host but the user must wait until the host
  583.  *                  accepts the connection.
  584.  *    
  585.  * Side effects:
  586.  *    A packet is sent to the remote host to initiate the connection
  587.  *    handshake.
  588.  *
  589.  *----------------------------------------------------------------------
  590.  */
  591.  
  592. ReturnStatus
  593. TCP_SocketConnect(sockPtr, remoteAddrPtr, initialize)
  594.     register Sock_SharedInfo    *sockPtr;    /* Initialized socket. */
  595.     Net_InetSocketAddr        *remoteAddrPtr;    /* Remote <address,port> to 
  596.                           * connect to. */
  597.     Boolean            initialize;    /* If TRUE, initialize the TCB*/
  598. {
  599.     TCPControlBlock    *tcbPtr;
  600.     Net_InetSocketAddr    remote;
  601.  
  602.     remote = *remoteAddrPtr;
  603.     /*
  604.      * The socket's can only connect once so if it's in the process of 
  605.      * connecting or is already connected, return an error.
  606.      */
  607.  
  608.     if ((sockPtr->state == CONNECTING) || (sockPtr->state == CONNECTED))  {
  609.     return(NET_ALREADY_CONNECTED);
  610.     }
  611.  
  612.  
  613.     /*
  614.      * A valid remote port must be specified.
  615.      */
  616.     if (remote.port == 0) {
  617.     return(NET_ADDRESS_NOT_AVAIL);
  618.     }
  619.  
  620.     /*
  621.      * If the wildcard address or the broadcast wildcard are given, then
  622.      * use the official address (explicit or broadcast) for the server.
  623.      */
  624.  
  625.     if (remote.address == Net_HostToNetInt(NET_INET_ANY_ADDR)) {
  626.     remote.address = Rte_GetOfficialAddr(FALSE);
  627.     } else if (remote.address == Net_HostToNetInt(NET_INET_BROADCAST_ADDR)) {
  628.     remote.address = Rte_GetOfficialAddr(TRUE);
  629.     }
  630.  
  631.     if (sockPtr->local.address == Net_HostToNetInt(NET_INET_ANY_ADDR)) {
  632.     Net_InetAddress    localAddr;
  633.  
  634.     /*
  635.      * The socket doesn't have a local address part yet so 
  636.      * use the official address for this server. Make sure the
  637.      * <local <address,port> and remote <address,port>> tuple is
  638.      * unique among all open TCP sockets.
  639.      */
  640.  
  641.     localAddr = Rte_GetOfficialAddr(FALSE);
  642.     if (Sock_Match(TCP_PROTO_INDEX, localAddr, 
  643.         sockPtr->local.port, remote.address, remote.port, FALSE) !=
  644.         (Sock_InfoPtr    ) NULL) {
  645.         return(NET_ADDRESS_IN_USE);
  646.     }
  647.  
  648.     /*
  649.      * The socket has a unique address tuple. 
  650.      * If a local port has not been chosen yet, assign an unused value.
  651.      */
  652.  
  653.     sockPtr->local.address = localAddr;
  654.     if (sockPtr->local.port == 0) {
  655.         sockPtr->local.port = GetPort(localAddr);
  656.     }
  657.     } else {
  658.     /*
  659.      * The socket has a valid local <address, port>. Make sure the
  660.      * the <local, remote> tuple is unique among all open TCP sockets.
  661.      */
  662.  
  663.     if (Sock_Match(TCP_PROTO_INDEX, sockPtr->local.address, 
  664.         sockPtr->local.port, remote.address, remote.port, FALSE) !=
  665.         (Sock_InfoPtr    ) NULL) {
  666.         return(NET_ADDRESS_IN_USE);
  667.     }
  668.     }
  669.     sockPtr->remote    = remote;
  670.     sockPtr->state    = CONNECTING;
  671.  
  672.     if (!initialize) {
  673.     /*
  674.      * The caller will handle the initialization.
  675.      */
  676.     return(SUCCESS);
  677.     } 
  678.  
  679.     stats.tcp.connAttempts++;
  680.     tcbPtr = (TCPControlBlock *) sockPtr->protoData;
  681.     TCPMakeTemplateHdr(sockPtr, tcbPtr);
  682.     tcbPtr->state = SYN_SENT;
  683.     tcbPtr->timer[TCP_TIMER_KEEP_ALIVE] = TCP_KEEP_TIME_INIT;
  684.     tcbPtr->send.initial = tcpISS;
  685.     tcpISS += TCP_INIT_SEND_SEQ_INCR/2;
  686.     TCP_SEND_SEQ_INIT(tcbPtr);
  687.     (void) TCPOutput(sockPtr, tcbPtr);
  688.  
  689.     /*
  690.      * Tell the client to wait until out request is accepted.
  691.      * The client should call Fs_Select waiting for the socket
  692.      * to become writable.
  693.      */
  694.     return(FS_WOULD_BLOCK);
  695. }
  696.  
  697. /*
  698.  *----------------------------------------------------------------------
  699.  *
  700.  * TCP_SocketListen --
  701.  *
  702.  *    Make the the TCP socket into a passive socket by changing to the 
  703.  *    LISTENING state. In passive mode, the socket can wait for connection
  704.  *    requests from remote hosts. The backlog argument specifies how
  705.  *    many requests can be queued and not be immediately refused.
  706.  *
  707.  * Results:
  708.  *    SUCCESS            - the operation was successful.
  709.  *    NET_BAD_OPERATION    - The socket was in the wrong state.
  710.  *
  711.  * Side effects:
  712.  *    The socket state is changed to LISTEN, a connect info struct
  713.  *    is allocated and initialized.
  714.  *
  715.  *----------------------------------------------------------------------
  716.  */
  717.  
  718. ReturnStatus
  719. TCP_SocketListen(sockPtr, backlog, userID)
  720.     Sock_SharedInfo    *sockPtr;
  721.     int            backlog;    /* How many pending requests to 
  722.                       * queue before rejecting them. */
  723.     int            userID;        /* User ID of the process. */
  724. {
  725.     TCPControlBlock        *tcbPtr;
  726.     register TCPConnectInfo    *connectPtr; 
  727.  
  728.     /*
  729.      * The socket must have been just created or had a local address given to
  730.      * in order to go into listen mode. This means the socket can't be
  731.      * connected.
  732.      */
  733.  
  734.     if (sockPtr->state == CREATED) {
  735.     ReturnStatus        status;
  736.     Net_InetSocketAddr    sockAddr;
  737.  
  738.     /*
  739.      * Have to give the socket a local address.
  740.      */
  741.     sockAddr.address = Net_HostToNetInt(NET_INET_ANY_ADDR);
  742.     sockAddr.port = 0;
  743.     status = TCP_SocketBind(sockPtr, &sockAddr, userID);
  744.     if (status != SUCCESS) {
  745.         return(status);
  746.     }
  747.     } else if (sockPtr->state != HAVE_LOCAL_ADDR) {
  748.     return(NET_BAD_OPERATION);
  749.     }
  750.  
  751.     /*
  752.      * Make sure the backlog value is in the proper range.
  753.      */
  754.     if (backlog <= 0) {
  755.     backlog = 1;
  756.     } else if (backlog > TCP_MAX_NUM_CONNECTS) {
  757.     backlog = TCP_MAX_NUM_CONNECTS;
  758.     }
  759.  
  760.     connectPtr = (TCPConnectInfo *) malloc(sizeof(TCPConnectInfo));
  761.     connectPtr->head = 0;
  762.     connectPtr->tail = 0;
  763.     /*
  764.      * The queue is circular so it requires 1 slot to be unused in order
  765.      * to tell if the queue is full.
  766.      */
  767.     connectPtr->maxQueueSize = backlog + 1;
  768.  
  769.     tcbPtr = (TCPControlBlock *) sockPtr->protoData;
  770.     tcbPtr->connectPtr    = connectPtr;
  771.     tcbPtr->state    = LISTEN;
  772.     sockPtr->state    = LISTENING;
  773.     return(SUCCESS);
  774. }
  775.  
  776.  
  777. /*
  778.  *----------------------------------------------------------------------
  779.  *
  780.  * TCP_SocketAccept --
  781.  *
  782.  *    This routine handles the first part of accepting a waiting connection 
  783.  *    request. If there's a waiting request, a token is returned in 
  784.  *    outBuffer. This token must be used with the NET_IOC_ACCEPT_CONN_2
  785.  *    ioctl to complete the connection.
  786.  *
  787.  * Results:
  788.  *    SUCCESS            - a connect token was returned in outBuffer.
  789.  *    NET_BAD_OPERATION    - the socket is in the listening state.
  790.  *    NET_NO_CONNECTS        - no pending connect requests.
  791.  *
  792.  * Side effects:
  793.  *    None.
  794.  *
  795.  *----------------------------------------------------------------------
  796.  */
  797.  
  798. ReturnStatus
  799. TCP_SocketAccept(sockPtr, outBuffer)
  800.     register Sock_SharedInfo    *sockPtr;    /* Listening socket. */
  801.     Address            outBuffer;    /* Place to hold connect token*/
  802. {
  803.     if (sockPtr->state != LISTENING) {
  804.     return(NET_BAD_OPERATION);
  805.     }
  806.  
  807.     if (!ConnQueueNotEmpty(sockPtr, TRUE)) {
  808.     return(NET_NO_CONNECTS);
  809.     }
  810.  
  811.     *(ClientData *) outBuffer = (ClientData) ConnQueueNext(sockPtr);
  812.     return(SUCCESS);
  813. }
  814.  
  815.  
  816. /*
  817.  *----------------------------------------------------------------------
  818.  *
  819.  * TCP_SocketDestroy --
  820.  *
  821.  *    Destroys all TCP-related memory allocated to a socket.
  822.  *
  823.  * Results:
  824.  *    None.
  825.  *
  826.  * Side effects:
  827.  *    TCB memory is deallocated.
  828.  *
  829.  *----------------------------------------------------------------------
  830.  */
  831.  
  832. void
  833. TCP_SocketDestroy(data)
  834.     ClientData    data;        /* Really a ptr to the TCB. */
  835. {
  836.     TCPControlBlock *tcbPtr;
  837.     tcbPtr = (TCPControlBlock *) data;
  838.  
  839.     /*
  840.      * The TCB apparently may be NULL if the process owning the socket
  841.      * was killed asynchronously, so check against this so we don't
  842.      * deference a NULL pointer.
  843.      */
  844.     if (tcbPtr == (TCPControlBlock *) NULL) {
  845.     (void) fprintf(stderr, "TCP_SocketDestroy: tcb == NULL\n");
  846.     return;
  847.     }
  848.  
  849.     if (tcbPtr->connectPtr != (TCPConnectInfo *)NULL) {
  850.     free((char *) tcbPtr->connectPtr);
  851.     }
  852.     if (tcbPtr->templatePtr != (Net_TCPHeader *)NULL) {
  853.     free((char *) tcbPtr->templatePtr);
  854.     }
  855.     if (tcbPtr->IPTemplatePtr != (Net_IPHeader *)NULL) {
  856.     free((char *) tcbPtr->IPTemplatePtr);
  857.     }
  858.     TCPCleanReassList(tcbPtr);
  859.     TCPCancelTimers(tcbPtr);
  860.  
  861.     free((char *) tcbPtr);
  862. }
  863.  
  864.  
  865. /*
  866.  *----------------------------------------------------------------------
  867.  *
  868.  * TCP_SocketShutdown --
  869.  *
  870.  *    This routine gracefully closes down a TCP connection.
  871.  *
  872.  * Results:
  873.  *    SUCCESS        - the operation was successful.
  874.  *    ?         - result from TCPOutput.
  875.  *
  876.  * Side effects:
  877.  *    None.
  878.  *
  879.  *----------------------------------------------------------------------
  880.  */
  881.  
  882. ReturnStatus
  883. TCP_SocketShutdown(sockPtr, how)
  884.     Sock_SharedInfo    *sockPtr;
  885.     int            how;       /* What operations to shut down. */
  886. {
  887.     register TCPControlBlock *tcbPtr;
  888.     tcbPtr = (TCPControlBlock *) sockPtr->protoData;
  889.  
  890.     Sock_StopSending(sockPtr);
  891.  
  892.     switch (how) {
  893.     case 0:
  894.         Sock_StopRecv(sockPtr);
  895.         break;
  896.  
  897.     case 1:
  898.         Sock_StopSending(sockPtr);
  899.         break;
  900.  
  901.     case 2:
  902.         Sock_StopRecv(sockPtr);
  903.         Sock_StopSending(sockPtr);
  904.         break;
  905.     }
  906.  
  907.     if (tcbPtr != (TCPControlBlock *) NULL) {
  908.     switch (tcbPtr->state) {
  909.         case CLOSED:
  910.         case LISTEN:
  911.         case SYN_SENT:
  912.         TCPCloseConnection(sockPtr, tcbPtr);
  913.         tcbPtr = (TCPControlBlock *) NULL;
  914.         break;
  915.  
  916.         case SYN_RECEIVED:
  917.         case ESTABLISHED:
  918.         tcbPtr->state = FIN_WAIT_1;
  919.         break;
  920.  
  921.         case CLOSE_WAIT:
  922.         tcbPtr->state = LAST_ACK;
  923.         break;
  924.  
  925.         case FIN_WAIT_2:
  926.         case TIME_WAIT:
  927.         Sock_Disconnected(sockPtr);
  928.         break;
  929.  
  930.         case FIN_WAIT_1:
  931.         case LAST_ACK:
  932.         break;
  933.     }
  934.     if (tcbPtr != (TCPControlBlock *) NULL) {
  935.         return(TCPOutput(sockPtr, tcbPtr));
  936.     }
  937.     }
  938.     return(SUCCESS);
  939. }
  940.  
  941.  
  942. /*
  943.  *----------------------------------------------------------------------
  944.  *
  945.  * TCP_SocketSetOpt --
  946.  *
  947.  *    This routine changes the value of a TCP socket option.
  948.  *
  949.  * Results:
  950.  *    SUCCESS        - the operation was successful.
  951.  *    GEN_INVALID_ARG - bad option or invalid buffer size.
  952.  *
  953.  * Side effects:
  954.  *    The tcb flags are updated.
  955.  *
  956.  *----------------------------------------------------------------------
  957.  */
  958.  
  959. ReturnStatus
  960. TCP_SocketSetOpt(sockPtr, optName, inBufSize, inBuffer)
  961.     Sock_SharedInfo    *sockPtr;
  962.     int        optName;        /* Option. */
  963.     int        inBufSize;        /* Size in bytes of inBuffer. */
  964.     Address    inBuffer;        /* Buffer containing input data. */
  965. {
  966.     TCPControlBlock *tcbPtr;
  967.  
  968.     /*
  969.      * We expect at least 4 bytes of data
  970.      * and this better be a TCP protocol socket,
  971.      * or it probably won't have a valid protoData field.
  972.      */
  973.     if ((inBufSize < sizeof(int)) ||
  974.     (sockPtr->protoIndex != TCP_PROTO_INDEX )) {
  975.     return(GEN_INVALID_ARG);
  976.     }
  977.  
  978.     tcbPtr = (TCPControlBlock *) sockPtr->protoData;
  979.  
  980.     switch (optName) {
  981.     case NET_OPT_TCP_NO_DELAY:
  982.         if (*(int *)inBuffer) {
  983.         tcbPtr->flags |= TCP_NO_DELAY;
  984.         } else {
  985.         tcbPtr->flags &= ~TCP_NO_DELAY;
  986.         }
  987.         break;
  988.  
  989.     case NET_OPT_TCP_MAX_SEG_SIZE:
  990.         return(GEN_INVALID_ARG);    /* not implemented yet. */
  991.         break;
  992.  
  993.     default:
  994.         return(GEN_INVALID_ARG);
  995.     }
  996.     return(SUCCESS);
  997. }
  998.  
  999.  
  1000. /*
  1001.  *----------------------------------------------------------------------
  1002.  *
  1003.  * TCP_SocketGetOpt --
  1004.  *
  1005.  *    This routine retreives the value of a TCP socket option.
  1006.  *
  1007.  * Results:
  1008.  *    SUCCESS        - the operation was successful.
  1009.  *    GEN_INVALID_ARG    - outbuffer too small or invalid option.
  1010.  *
  1011.  * Side effects:
  1012.  *    None.
  1013.  *
  1014.  *----------------------------------------------------------------------
  1015.  */
  1016.  
  1017. ReturnStatus
  1018. TCP_SocketGetOpt(sockPtr, optName, outBufSize, outBuffer)
  1019.     Sock_SharedInfo    *sockPtr;
  1020.     int        optName;        /* Option. */
  1021.     int        outBufSize;        /* Size in bytes of outBuffer. */
  1022.     Address    outBuffer;        /* Buffer to store output data. */
  1023. {
  1024.     TCPControlBlock *tcbPtr;
  1025.     tcbPtr = (TCPControlBlock *) sockPtr->protoData;
  1026.  
  1027.     /*
  1028.      * We want to return at least  4 bytes of data.
  1029.      */
  1030.     if (outBufSize < sizeof(int)) {
  1031.     return(GEN_INVALID_ARG);
  1032.     }
  1033.  
  1034.     switch (optName) {
  1035.     case NET_OPT_TCP_NO_DELAY:
  1036.         *(int *)outBuffer = tcbPtr->flags & TCP_NO_DELAY;
  1037.         break;
  1038.  
  1039.     case NET_OPT_TCP_MAX_SEG_SIZE:
  1040.         *(int *)outBuffer = tcbPtr->maxSegSize;
  1041.         break;
  1042.  
  1043.     default:
  1044.         return(GEN_INVALID_ARG);
  1045.     }
  1046.     return(SUCCESS);
  1047. }
  1048.  
  1049.  
  1050. /*
  1051.  *----------------------------------------------------------------------
  1052.  *
  1053.  * GetPort --
  1054.  *
  1055.  *    Given a local address, this routine finds a unused port and makes 
  1056.  *    sure it doesn't doesn't conflict with an existing socket's 
  1057.  *    binding address.
  1058.  *
  1059.  * Results:
  1060.  *    A new port #.
  1061.  *
  1062.  * Side effects:
  1063.  *    The port value is incremented.
  1064.  *
  1065.  *----------------------------------------------------------------------
  1066.  */
  1067.  
  1068. static unsigned int
  1069. GetPort(localAddr)
  1070.     Net_InetAddress    localAddr;
  1071. {
  1072.     static unsigned int port = INET_PRIV_PORTS;
  1073.     unsigned    int        netPort;
  1074.     unsigned    int        anyAddr = Net_HostToNetInt(NET_INET_ANY_ADDR);
  1075.  
  1076.     do {
  1077.     port++;
  1078.     if ((port < INET_PRIV_PORTS) || (port > INET_SERVER_PORTS)) {
  1079.         port = INET_PRIV_PORTS;
  1080.     }
  1081.     netPort = Net_HostToNetShort(port);
  1082.     } while (Sock_Match(TCP_PROTO_INDEX, localAddr, netPort, anyAddr, 0, 
  1083.             FALSE) != (Sock_InfoPtr    ) NULL);
  1084.     return(netPort);
  1085. }
  1086.  
  1087.  
  1088. /*
  1089.  *----------------------------------------------------------------------
  1090.  *
  1091.  * TCPCloneConnection --
  1092.  *
  1093.  *    Creates a new socket for a connected TCP socket in the 
  1094.  *    listening state.
  1095.  *
  1096.  * Results:
  1097.  *    A pointer to the Sock_SharedInfo struct for the new socket or
  1098.  *    NULL, if there was a problem.
  1099.  *
  1100.  * Side effects:
  1101.  *    A new TCP socket was created.
  1102.  *
  1103.  *----------------------------------------------------------------------
  1104.  */
  1105.  
  1106. Sock_InfoPtr    
  1107. TCPCloneConnection(sockPtr, localAddr, localPort, remoteAddr, remotePort)
  1108.     Sock_SharedInfo    *sockPtr;    /* Socket to be cloned. */
  1109.     Net_InetAddress    localAddr;    /* The new socket's local address,port*/
  1110.     unsigned int    localPort;
  1111.     Net_InetAddress    remoteAddr;    /* The remote host's address, port. */
  1112.     unsigned int    remotePort;
  1113. {
  1114.     Sock_SharedInfo    *newSockPtr;
  1115.     Net_InetSocketAddr    sockAddr;
  1116.  
  1117.     if (sockPtr->state != LISTENING) {
  1118.     panic(
  1119.         "TCPCloneConnection: old socket not listening %d\n",
  1120.         sockPtr->state);
  1121.     }
  1122.  
  1123.     /*
  1124.      * See if there's space to accept the connection.
  1125.      */
  1126.     if (ConnQueueFull(sockPtr)) {
  1127.     return((Sock_InfoPtr    )NULL);
  1128.     }
  1129.  
  1130.     newSockPtr = Sock_Clone(sockPtr, TRUE);
  1131.     /*
  1132.      * We don't know the user ID of the client, so just lie and
  1133.      * say it's the super-user. This is not a security hole because
  1134.      * the true permissions check was made when the socket was bound.
  1135.      */
  1136.     (void) TCP_SocketOpen(newSockPtr, PROC_SUPER_USER_ID);
  1137.  
  1138.     /*
  1139.      * Connect the socket to the remote peer. If the connect routine
  1140.      * discovers a problem, then destroy the new socket.
  1141.      */
  1142.  
  1143.     newSockPtr->local.address = localAddr;
  1144.     newSockPtr->local.port = localPort;
  1145.     newSockPtr->state = HAVE_LOCAL_ADDR;
  1146.  
  1147.     sockAddr.address = remoteAddr;
  1148.     sockAddr.port = remotePort;
  1149.     if (TCP_SocketConnect(newSockPtr, &sockAddr, FALSE) != SUCCESS) {
  1150.     Sock_Destroy(newSockPtr);
  1151.     return((Sock_InfoPtr    )NULL);
  1152.     }
  1153.  
  1154.     ConnQueueAppend(sockPtr, newSockPtr);
  1155.  
  1156.     return(newSockPtr);
  1157. }
  1158.  
  1159.  
  1160.  
  1161. /*
  1162.  *----------------------------------------------------------------------
  1163.  *
  1164.  * TCPSockToTCB --
  1165.  *
  1166.  *    Returns the pointer to the TCP control block for a TCP socket.
  1167.  *
  1168.  * Results:
  1169.  *    The tcb pointer.
  1170.  *
  1171.  * Side effects:
  1172.  *    None.
  1173.  *
  1174.  *----------------------------------------------------------------------
  1175.  */
  1176.  
  1177. TCPControlBlock *
  1178. TCPSockToTCB(sockPtr)
  1179.     Sock_InfoPtr    sockPtr;
  1180. {
  1181.     if (sockPtr->protoIndex != TCP_PROTO_INDEX) {
  1182.     panic("TCPSockToTCB: bad socket ptr\n");
  1183.     }
  1184.     return((TCPControlBlock *) sockPtr->protoData);
  1185. }
  1186.  
  1187. /*
  1188.  *----------------------------------------------------------------------
  1189.  *
  1190.  * TCPMakeTemplateHdr --
  1191.  *
  1192.  *    Create template to be used to send tcp packets on a connection.
  1193.  *    Call after host entry created, allocates an mbuf and fills
  1194.  *    in a skeletal tcp/ip header, minimizing the amount of work
  1195.  *    necessary when the connection is used.
  1196.  *
  1197.  * Results:
  1198.  *    None.
  1199.  *
  1200.  * Side effects:
  1201.  *    Memory for the headers is allocated.
  1202.  *
  1203.  *----------------------------------------------------------------------
  1204.  */
  1205.  
  1206. void
  1207. TCPMakeTemplateHdr(sockPtr, tcbPtr)
  1208.     Sock_SharedInfo     *sockPtr;
  1209.     TCPControlBlock    *tcbPtr;
  1210. {
  1211.     register Net_TCPHeader *tcpHdrPtr;
  1212.     register Net_IPHeader *ipHdrPtr;
  1213.  
  1214.     ipHdrPtr = (Net_IPHeader *) malloc(sizeof(Net_IPHeader));
  1215.     ipHdrPtr->protocol    = NET_IP_PROTOCOL_TCP;
  1216.     ipHdrPtr->source    = sockPtr->local.address;
  1217.     ipHdrPtr->dest    = sockPtr->remote.address;
  1218.     tcbPtr->IPTemplatePtr = ipHdrPtr;
  1219.  
  1220.     tcpHdrPtr = (Net_TCPHeader *) malloc(sizeof(Net_TCPHeader));
  1221.     tcpHdrPtr->srcPort    = sockPtr->local.port;
  1222.     tcpHdrPtr->destPort    = sockPtr->remote.port;
  1223.     tcpHdrPtr->seqNum    = 0;
  1224.     tcpHdrPtr->ackNum    = 0;
  1225.     tcpHdrPtr->dataOffset = sizeof(Net_TCPHeader) / 4;
  1226.     tcpHdrPtr->flags    = 0;
  1227.     tcpHdrPtr->window    = 0;
  1228.     tcpHdrPtr->checksum    = 0;
  1229.     tcpHdrPtr->urgentOffset= 0;
  1230.     tcbPtr->templatePtr = tcpHdrPtr;
  1231. }
  1232.  
  1233. /*
  1234.  *----------------------------------------------------------------------
  1235.  *
  1236.  * TCPDropConnection --
  1237.  *
  1238.  *    Drop a TCP connection, reporting the specified error to the user.
  1239.  *    If the connection is synchronized, then send a RESET to the remote
  1240.  *    peer.
  1241.  *
  1242.  * Results:
  1243.  *    None.
  1244.  *
  1245.  * Side effects:
  1246.  *    The TCB is destroyed.
  1247.  *
  1248.  *----------------------------------------------------------------------
  1249.  */
  1250.  
  1251. void
  1252. TCPDropConnection(sockPtr, tcbPtr, status)
  1253.     Sock_SharedInfo        *sockPtr;
  1254.     register TCPControlBlock    *tcbPtr;    /* TCB to be dropped. */
  1255.     ReturnStatus        status;        /* Error to give
  1256.                            to client. */
  1257. {
  1258.     if (tcbPtr == (TCPControlBlock *) NULL) {
  1259.     (void) fprintf(stderr, "TCPDropConnection: tcb == NULL\n");
  1260.     return;
  1261.     }
  1262.     if (TCP_HAVE_RECVD_SYN(tcbPtr->state)) {
  1263.     tcbPtr->state = CLOSED;
  1264.     (void) TCPOutput(sockPtr, tcbPtr);
  1265.     stats.tcp.drops++;
  1266.     } else {
  1267.     stats.tcp.connDrops++;
  1268.     }
  1269.     Sock_SetError(sockPtr, status);
  1270.     TCPCloseConnection(sockPtr, tcbPtr);
  1271. }
  1272.  
  1273. /*
  1274.  *----------------------------------------------------------------------
  1275.  *
  1276.  * TCPCloseConnection --
  1277.  *
  1278.  *    Close a TCP control block by  discarding all space held by the tcb,
  1279.  *    and waking any waiters.
  1280.  *
  1281.  * Results:
  1282.  *    None.
  1283.  *
  1284.  * Side effects:
  1285.  *    The TCB and socket may be destroyed.
  1286.  *
  1287.  *----------------------------------------------------------------------
  1288.  */
  1289.  
  1290. void
  1291. TCPCloseConnection(sockPtr, tcbPtr)
  1292.     Sock_SharedInfo        *sockPtr;
  1293.     register TCPControlBlock     *tcbPtr;
  1294. {
  1295.     if (!Sock_HasUsers(sockPtr)) {
  1296.     Sock_Destroy(sockPtr);
  1297.     } else {
  1298.     TCP_SocketDestroy((ClientData) tcbPtr);
  1299.     sockPtr->protoData = (ClientData) NULL;
  1300.     Sock_Disconnected(sockPtr);
  1301.     sockPtr->local.address = 0;
  1302.     sockPtr->local.port = 0;
  1303.     sockPtr->remote.address = 0;
  1304.     sockPtr->remote.port = 0;
  1305.     }
  1306.     stats.tcp.closed++;
  1307. }
  1308.  
  1309. /*
  1310.  *----------------------------------------------------------------------
  1311.  *
  1312.  * TCP_Quench --
  1313.  *
  1314.  *    When a source quench is received, close congestion window
  1315.  *    to one segment.  We will gradually open it again as we proceed.
  1316.  *
  1317.  * Results:
  1318.  *    None.
  1319.  *
  1320.  * Side effects:
  1321.  *    None.
  1322.  *
  1323.  *----------------------------------------------------------------------
  1324.  */
  1325.  
  1326. TCP_Quench(tcbPtr)
  1327.     TCPControlBlock *tcbPtr;
  1328. {
  1329.     if (tcbPtr != NULL) {
  1330.     tcbPtr->send.congWindow = tcbPtr->maxSegSize;
  1331.     }
  1332. }
  1333.  
  1334.  
  1335. /*
  1336.  *----------------------------------------------------------------------
  1337.  *
  1338.  * ConnQueueFull --
  1339.  *
  1340.  *    Checks if the connection queue of a listening socket is full.
  1341.  *
  1342.  * Results:
  1343.  *    TRUE    - the queue is full.
  1344.  *    FALSE    - the queue is not full.
  1345.  *
  1346.  * Side effects:
  1347.  *    None.
  1348.  *
  1349.  *----------------------------------------------------------------------
  1350.  */
  1351.  
  1352. static Boolean
  1353. ConnQueueFull(sockPtr)
  1354.     Sock_InfoPtr    sockPtr;    /* Listening socket. */
  1355. {
  1356.     register TCPConnectInfo *connPtr;
  1357.     connPtr = ((TCPControlBlock *)sockPtr->protoData)->connectPtr;
  1358.  
  1359.     if (((connPtr->tail+1) % connPtr->maxQueueSize) == connPtr->head) {
  1360.     return(TRUE);
  1361.     } 
  1362.     return(FALSE);
  1363. }
  1364.  
  1365.  
  1366. /*
  1367.  *----------------------------------------------------------------------
  1368.  *
  1369.  * ConnQueueNotEmpty --
  1370.  *
  1371.  *    Sees if the connection queue of a listening socket is not empty.
  1372.  *    If the mustBeConnected argument is TRUE, then if the queue
  1373.  *    is not empty, make sure the first socket in the queue is
  1374.  *    connected.
  1375.  *
  1376.  * Results:
  1377.  *    TRUE    - the queue is not empty.
  1378.  *    FALSE    - the queue is empty.
  1379.  *
  1380.  * Side effects:
  1381.  *    None.
  1382.  *
  1383.  *----------------------------------------------------------------------
  1384.  */
  1385.  
  1386. static Boolean
  1387. ConnQueueNotEmpty(sockPtr, mustBeConnected)
  1388.     Sock_InfoPtr    sockPtr;     /* Listening socket. */
  1389.     Boolean        mustBeConnected; /* If TRUE, make sure the first socket
  1390.                   * on the connection queue is connected. */
  1391. {
  1392.     register TCPConnectInfo *connPtr;
  1393.     connPtr = ((TCPControlBlock *)sockPtr->protoData)->connectPtr;
  1394.  
  1395.     if (connPtr->tail != connPtr->head) {
  1396.     if (!mustBeConnected) {
  1397.         return(TRUE);
  1398.     }
  1399.     /*
  1400.      * If the socket is still connecting, don't return TRUE yet.
  1401.      */
  1402.     if (connPtr->queue[connPtr->head]->state == CONNECTED) {
  1403.         return(TRUE);
  1404.     }
  1405.     } 
  1406.     return(FALSE);
  1407. }
  1408.  
  1409.  
  1410. /*
  1411.  *----------------------------------------------------------------------
  1412.  *
  1413.  * ConnQueueAppend --
  1414.  *
  1415.  *    Appends a sockPtr to a connection queue of listening socket.
  1416.  *
  1417.  * Results:
  1418.  *    None.
  1419.  *
  1420.  * Side effects:
  1421.  *    The queue is lengthened by 1.
  1422.  *
  1423.  *----------------------------------------------------------------------
  1424.  */
  1425.  
  1426. static void
  1427. ConnQueueAppend(sockPtr, newSockPtr)
  1428.     Sock_InfoPtr    sockPtr;        /* Listening socket. */
  1429.     Sock_InfoPtr    newSockPtr;    /* Socket for the new connection. */
  1430. {
  1431.     register TCPConnectInfo *connPtr;
  1432.     connPtr = ((TCPControlBlock *)sockPtr->protoData)->connectPtr;
  1433.     
  1434.     connPtr->queue[connPtr->tail] = newSockPtr;
  1435.     connPtr->tail = (connPtr->tail+1) % connPtr->maxQueueSize;
  1436. }
  1437.  
  1438.  
  1439. /*
  1440.  *----------------------------------------------------------------------
  1441.  *
  1442.  * ConnQueueNext --
  1443.  *
  1444.  *    Gets the next sockPtr on the connection queue of listening socket.
  1445.  *
  1446.  * Results:
  1447.  *    A Sock_SharedInfo ptr.
  1448.  *
  1449.  * Side effects:
  1450.  *    The queue is shortened by 1.
  1451.  *
  1452.  *----------------------------------------------------------------------
  1453.  */
  1454.  
  1455. static Sock_InfoPtr    
  1456. ConnQueueNext(sockPtr)
  1457.     Sock_InfoPtr    sockPtr;        /* Listening socket. */
  1458. {
  1459.     Sock_InfoPtr    newPtr;
  1460.     register TCPConnectInfo *connPtr;
  1461.  
  1462.     connPtr = ((TCPControlBlock *)sockPtr->protoData)->connectPtr;
  1463.     
  1464.     newPtr = connPtr->queue[connPtr->head];
  1465.     connPtr->head = (connPtr->head+1) % connPtr->maxQueueSize;
  1466.     return(newPtr);
  1467. }
  1468.